package com.linkdood.app.service.impl;

import com.linkdood.app.constants.SystemNoticeConstants;
import com.linkdood.app.domain.*;
import com.linkdood.app.service.*;
import com.linkdood.app.service.ddio.DdioOrgSyncResponseBody;
import com.linkdood.app.service.ddio.DdioUserSyncResponseBody;
import com.linkdood.app.utils.DdioConverUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author cfj
 */
@Service
@Slf4j
public class DdioSynchronize implements ISynchronize {

    private final DdioService ddioService;

    private final OrganizationService organizationService;

    private final SettingService settingService;

    private final UserService userService;

    private final UserDataService userDataService;

    private final UserOrganizationService userOrganizationService;

    private final SystemNoticeService systemNoticeService;

    public DdioSynchronize(DdioService ddioService,
                           OrganizationService organizationService,
                           SettingService settingService,
                           UserService userService,
                           UserDataService userDataService,
                           UserOrganizationService userOrganizationService,
                           SystemNoticeService systemNoticeService) {
        this.ddioService = ddioService;
        this.organizationService = organizationService;
        this.settingService = settingService;
        this.userService = userService;
        this.userDataService = userDataService;
        this.userOrganizationService = userOrganizationService;
        this.systemNoticeService = systemNoticeService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncAllUser(ThirdParty thirdParty) {
        reloadUser(thirdParty);
        syncUsers(thirdParty, true);
        systemNoticeService.save(SystemNoticeConstants.SYSTEM_NOTICE_TYPE_USER_SYNC_SUCCESS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncIncrementUser(ThirdParty thirdParty) {
        syncUsers(thirdParty, false);
        systemNoticeService.save(SystemNoticeConstants.SYSTEM_NOTICE_TYPE_ORGANIZATION_INCREMENT_SYNC_DONE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncAllOrg(ThirdParty thirdParty) {
        Map<String, Object> map = new HashMap<>(1);
        map.put("third_party_id", thirdParty.getId());
        organizationService.removeByMap(map);
        List<DoodOrganization> organizations = ddioService.listOrganizations(thirdParty.getId());
        if (CollectionUtils.isEmpty(organizations)) {
            return;
        }
        for (DoodOrganization doodOrganization : organizations) {
            Organization organization = DdioConverUtil.convert(doodOrganization);
            organization.setThirdPartyId(thirdParty.getId());
            organizationService.save(organization);
        }
        systemNoticeService.save(SystemNoticeConstants.SYSTEM_NOTICE_TYPE_ORGANIZATION_SYNC_SUCCESS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncIncrementOrg(ThirdParty thirdParty) {
        String version = settingService.getOrgChangeVersion();
        List<DdioOrgSyncResponseBody.DdioSyncOrg> orgList = ddioService.syncOrganizations(thirdParty.getId(), version);
        if (CollectionUtils.isEmpty(orgList)) {
            return;
        }
        for (DdioOrgSyncResponseBody.DdioSyncOrg org : orgList) {
            // 更新组织信息
            update(thirdParty.getId(), org);
            if (org.getChangeVersion() != null) {
                settingService.updateOrgChangeVersion(String.valueOf(org.getChangeVersion()));
            }
        }
        systemNoticeService.save(SystemNoticeConstants.SYSTEM_NOTICE_TYPE_USER_INCREMENT_SYNC_DONE);
    }

    /**
     * 拉取所有用户
     */
    private void reloadUser(ThirdParty thirdParty) {
        for (DoodUser doodUser : ddioService.listUsers(thirdParty.getId())) {
            Optional<User> optionalUser = userService.getBySourceId(thirdParty.getId(), doodUser.getUserID());
            UserData userData = DdioConverUtil.convertUserData(doodUser);

            // 如果已经存在则更新  如果不存在添加
            if (optionalUser.isPresent()) {
                User oldUser = optionalUser.get();
                if (9 == doodUser.getStatus()) {
                    oldUser.setSourceDeleted(true);
                } else {
                    oldUser.setSourceDeleted(false);
                }
                oldUser.setDisplayName(doodUser.getName());
                userService.updateById(oldUser);

                // 更新详情信息
                UserData oldUserData = userDataService.getUserDataByUserId(oldUser.getId());
                if (oldUserData != null) {
                    userData.setId(oldUserData.getId());
                    userDataService.updateById(userData);
                } else {
                    userData.setUserId(oldUser.getId());
                    userDataService.save(userData);
                }
            } else {
                User user = new User();
                user.setDeleted(false);
                user.setDirty(false);
                user.setDisplayName(doodUser.getName());
                if (9 == doodUser.getStatus()) {
                    user.setSourceDeleted(true);
                } else {
                    user.setSourceDeleted(false);
                }
                user.setSourceId(doodUser.getUserID());
                user.setThirdPartyId(thirdParty.getId());
                userService.save(user);

                userData.setUserId(user.getId());
                userDataService.save(userData);
            }

            // 平铺用户组织信息
            userOrganizationService.deleteByUserId(userData.getUserId());
            String orgIds = userData.getOrgId();
            log.debug("deal user_organize info, userId : {}, orgIds : {}", userData.getUserId(), orgIds);
            if (StringUtils.isNotBlank(orgIds)) {
                String[] orgs = orgIds.split(",");
                for (String orgId : orgs) {
                    if (StringUtils.isNotBlank(orgId)) {
                        UserOrganization userOrganization = new UserOrganization();
                        userOrganization.setUserId(userData.getUserId());
                        userOrganization.setOrgId(orgId);
                        userOrganizationService.save(userOrganization);
                    }
                }
            }
        }
    }

    /**
     * 增量同步用户
     */
    private void syncUsers(ThirdParty thirdParty, boolean all) {
        String version = "1";
        if (!all) {
            version = settingService.getUserChangeVersion();
        }
        List<DdioUserSyncResponseBody.DdioSyncUser> users = ddioService.syncUsers(thirdParty.getId(), version);
        if (CollectionUtils.isEmpty(users)) {
            return;
        }

        for (DdioUserSyncResponseBody.DdioSyncUser user : users) {
            update(thirdParty.getId(), user);
            if (user.getChangeVersion() != null) {
                settingService.updateUserChangeVersion(String.valueOf(user.getChangeVersion()));
            }
        }
    }

    /**
     * 同步更新组织信息
     */
    public void update(String thirdPartyId, DdioOrgSyncResponseBody.DdioSyncOrg org) {
        Organization organization = organizationService.getByOrgId(thirdPartyId, org.getOrgId());
        if (org.getEnterpriseID() != null) {
            organization.setEnterpriseId(String.valueOf(org.getEnterpriseID()));
        }
        if (1 != org.getOrgStatus()) {
            organizationService.removeById(organization.getId());
            return;
        }
        organization = DdioConverUtil.convertSyncOrg(organization, org);
        if (organization.getId() != null) {
            organizationService.updateById(organization);
        } else {
            organizationService.save(organization);
        }
    }

    /**
     * 同步更新 dood 用户
     */
    @Transactional(rollbackFor = Exception.class)
    public void update(String thirdPartyId, DdioUserSyncResponseBody.DdioSyncUser ddioUser) {
        Optional<User> optionalUser = userService.getBySourceId(thirdPartyId, ddioUser.getUserId());
        String userStatusDeleted = "9";
        if (userStatusDeleted.equals(ddioUser.getStatus())) {
            if (optionalUser.isPresent()) {
                User oldUser = optionalUser.get();
                oldUser.setSourceDeleted(true);
                userService.updateById(oldUser);
            }
            return;
        }

        UserData userData = new UserData();
        userData = DdioConverUtil.convertSyncUser(userData, ddioUser);

        if (!optionalUser.isPresent()) {
            // 新注册用户
            User newUser = new User();
            newUser.setThirdPartyId(thirdPartyId);
            newUser.setDirty(false);
            newUser.setDeleted(false);
            newUser.setSourceDeleted(false);
            newUser.setDisplayName(ddioUser.getName());
            if (ddioUser.getChangeVersion() != null) {
                newUser.setVersion(ddioUser.getChangeVersion().toString());
            }
            newUser.setSourceId(ddioUser.getUserId());
            userService.save(newUser);
            userData.setUserId(newUser.getId());
            userDataService.save(userData);
        } else {
            User newUser = optionalUser.get();
            newUser.setDisplayName(ddioUser.getName());
            if (ddioUser.getChangeVersion() != null) {
                newUser.setVersion(ddioUser.getChangeVersion().toString());
            }
            userService.updateById(newUser);
            Optional<UserData> optionalUserData = userDataService.getByUserId(newUser.getId());
            if (optionalUserData.isPresent()) {
                userData.setId(optionalUserData.get().getId());
                userDataService.updateById(userData);
            } else {
                userData.setUserId(newUser.getId());
                userDataService.save(userData);
            }
        }
    }
}
